package com.itheima.behavior.strategy;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itheima.apis.book.IBookClient;
import com.itheima.behavior.config.KafkaConfig;
import com.itheima.common.redis.CacheService;
import com.itheima.model.behavior.pojos.UserBehavior;
import com.itheima.model.behavior.vos.RecommendItemVo;
import com.itheima.model.common.dtos.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 冷启动策略
 * 处理新用户、新图书的推荐问题
 */
@Slf4j
@Component
public class ColdStartStrategy {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private IBookClient bookClient;

    /**
     * 判断是否为冷启动用户
     * @param userId 用户ID
     * @return true-冷启动用户，false-正常用户
     */
    public boolean isColdStartUser(Integer userId) {
        if (userId == null) {
            return true;
        }

        // 检查用户行为数量
        long behaviorCount = mongoTemplate.count(
                new Query(Criteria.where("userId").is(userId)),
                UserBehavior.class);

        // 少于5条行为记录认为是冷启动用户
        return behaviorCount < 5;
    }

    /**
     * 获取冷启动推荐
     * 策略组合：
     * 1. 热门图书 (40%)
     * 2. 新书推荐 (30%) 
     * 3. 高评分图书 (30%)
     * 
     * @param limit 推荐数量
     * @param excludeIds 排除的图书ID
     * @return 推荐列表
     */
    public List<RecommendItemVo> getColdStartRecommendations(Integer limit, Set<Integer> excludeIds) {
        log.info("执行冷启动推荐策略: limit={}", limit);

        List<RecommendItemVo> recommendations = new ArrayList<>();

        try {
            // 1. 热门图书 (40%)
            int hotCount = (int) (limit * 0.4);
            List<RecommendItemVo> hotBooks = getHotBooks(hotCount, excludeIds);
            hotBooks.forEach(book -> {
                book.setRecommendReason("热门好书推荐");
                book.setAlgorithmType("cold_start_hot");
            });
            recommendations.addAll(hotBooks);

            // 2. 新书推荐 (30%)
            int newCount = (int) (limit * 0.3);
            List<RecommendItemVo> newBooks = getNewBooks(newCount, excludeIds);
            newBooks.forEach(book -> {
                book.setRecommendReason("发现新书");
                book.setAlgorithmType("cold_start_new");
            });
            recommendations.addAll(newBooks);

            // 3. 分类多样化推荐 (30%) - 从多个分类选择
            int diverseCount = limit - recommendations.size();
            List<RecommendItemVo> diverseBooks = getDiverseBooks(diverseCount, excludeIds);
            diverseBooks.forEach(book -> {
                book.setRecommendReason("精选推荐");
                book.setAlgorithmType("cold_start_diverse");
            });
            recommendations.addAll(diverseBooks);

            // 去重并限制数量
            recommendations = deduplicateAndLimit(recommendations, limit);

            // 如果推荐数量仍不足，补充热门图书
            if (recommendations.size() < limit) {
                List<RecommendItemVo> moreHotBooks = getHotBooks(
                        limit - recommendations.size(), 
                        getBookIds(recommendations));
                recommendations.addAll(moreHotBooks);
            }

            log.info("冷启动推荐完成: count={}", recommendations.size());
            return recommendations;

        } catch (Exception e) {
            log.error("冷启动推荐失败", e);
            // 失败时返回热门图书
            return getHotBooks(limit, excludeIds);
        }
    }

    /**
     * 获取热门图书
     */
    private List<RecommendItemVo> getHotBooks(int limit, Set<Integer> excludeIds) {
        try {
            Set<String> topBookIds = cacheService.zReverseRange(
                    KafkaConfig.Keys.BOOK_HOT_RANKING, 
                    0, 
                    limit + excludeIds.size() + 10);

            if (topBookIds == null || topBookIds.isEmpty()) {
                return new ArrayList<>();
            }

            List<RecommendItemVo> books = new ArrayList<>();
            for (String bookIdStr : topBookIds) {
                if (books.size() >= limit) {
                    break;
                }

                try {
                    Integer bookId = Integer.parseInt(bookIdStr);
                    if (excludeIds.contains(bookId)) {
                        continue;
                    }

                    ResponseResult result = bookClient.getBookVo(bookId);
                    if (result != null && result.getCode() == 200 && result.getData() != null) {
                        JSONObject bookInfo = JSON.parseObject(JSON.toJSONString(result.getData()));
                        Double score = cacheService.zScore(KafkaConfig.Keys.BOOK_HOT_RANKING, bookIdStr);

                        RecommendItemVo item = buildRecommendItem(bookInfo, score);
                        books.add(item);
                        excludeIds.add(bookId);
                    }
                } catch (NumberFormatException e) {
                    log.debug("跳过无效的bookId: {}", bookIdStr);
                }
            }

            return books;

        } catch (Exception e) {
            log.error("获取热门图书失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取新书
     */
    private List<RecommendItemVo> getNewBooks(int limit, Set<Integer> excludeIds) {
        try {
            ResponseResult result = bookClient.getNewBooks(1, limit + 10);
            if (result == null || result.getCode() != 200 || result.getData() == null) {
                log.warn("获取新书失败: result={}", result != null ? result.getCode() : "null");
                return new ArrayList<>();
            }

            // result.getData() 直接就是 List<Book>，不需要再解析 records
            List<JSONObject> books = JSON.parseArray(JSON.toJSONString(result.getData()), JSONObject.class);
            
            if (books == null || books.isEmpty()) {
                log.warn("获取新书返回空列表");
                return new ArrayList<>();
            }

            log.info("获取到{}本新书，需要过滤后返回{}本", books.size(), limit);

            return books.stream()
                    .filter(book -> !excludeIds.contains(book.getInteger("id")))
                    .limit(limit)
                    .map(book -> {
                        excludeIds.add(book.getInteger("id"));
                        return buildRecommendItem(book, 0.0);
                    })
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("获取新书失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取多样化推荐（从不同分类选择）
     */
    private List<RecommendItemVo> getDiverseBooks(int limit, Set<Integer> excludeIds) {
        try {
            // 从阅读排行榜获取（相比热度榜更多样化）
            Set<String> bookIds = cacheService.zReverseRange(
                    KafkaConfig.Keys.BOOK_READ_RANKING, 
                    0, 
                    limit + 10);

            if (bookIds == null || bookIds.isEmpty()) {
                return new ArrayList<>();
            }

            List<RecommendItemVo> books = new ArrayList<>();
            Set<String> addedCategories = new HashSet<>(); // 记录已添加的分类

            for (String bookIdStr : bookIds) {
                if (books.size() >= limit) {
                    break;
                }

                try {
                    Integer bookId = Integer.parseInt(bookIdStr);
                    if (excludeIds.contains(bookId)) {
                        continue;
                    }

                    ResponseResult result = bookClient.getBookVo(bookId);
                    if (result != null && result.getCode() == 200 && result.getData() != null) {
                        JSONObject bookInfo = JSON.parseObject(JSON.toJSONString(result.getData()));
                        String category = bookInfo.getString("categoryName");

                        // 尽量选择不同分类的书（增加多样性）
                        if (addedCategories.size() < limit && !addedCategories.contains(category)) {
                            addedCategories.add(category);
                            RecommendItemVo item = buildRecommendItem(bookInfo, 0.0);
                            books.add(item);
                            excludeIds.add(bookId);
                        } else if (addedCategories.size() >= limit / 2) {
                            // 当分类足够多样后，可以重复分类
                            RecommendItemVo item = buildRecommendItem(bookInfo, 0.0);
                            books.add(item);
                            excludeIds.add(bookId);
                        }
                    }
                } catch (NumberFormatException e) {
                    log.debug("跳过无效的bookId: {}", bookIdStr);
                }
            }

            return books;

        } catch (Exception e) {
            log.error("获取多样化推荐失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取基于流行分类的推荐（新用户引导）
     * @param limit 推荐数量
     * @return 推荐列表
     */
    public List<RecommendItemVo> getPopularCategoryRecommendations(Integer limit) {
        log.info("获取流行分类推荐: limit={}", limit);

        try {
            // 获取最受欢迎的分类（基于阅读次数）
            List<String> popularCategories = getPopularCategories(5);
            
            List<RecommendItemVo> recommendations = new ArrayList<>();
            Set<Integer> addedBookIds = new HashSet<>();
            int booksPerCategory = Math.max(1, limit / popularCategories.size());

            for (String category : popularCategories) {
                if (recommendations.size() >= limit) {
                    break;
                }

                // 从每个流行分类获取几本书
                List<RecommendItemVo> categoryBooks = getBooksFromPopularCategory(
                        category, booksPerCategory, addedBookIds);
                
                categoryBooks.forEach(book -> {
                    book.setRecommendReason("探索" + category + "类好书");
                    book.setAlgorithmType("cold_start_category");
                });
                
                recommendations.addAll(categoryBooks);
            }

            return recommendations;

        } catch (Exception e) {
            log.error("获取流行分类推荐失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取最受欢迎的分类
     */
    private List<String> getPopularCategories(int limit) {
        // TODO: 从统计数据获取热门分类
        // 这里返回一些常见分类作为默认值
        return Arrays.asList("文学小说", "历史", "科幻小说", "技术", "经济");
    }

    /**
     * 从流行分类获取图书
     */
    private List<RecommendItemVo> getBooksFromPopularCategory(
            String category, int limit, Set<Integer> excludeIds) {
        // TODO: 实现基于分类名称的图书查询
        // 目前返回空列表
        return new ArrayList<>();
    }

    /**
     * 构建推荐项
     */
    private RecommendItemVo buildRecommendItem(JSONObject bookInfo, Double score) {
        return RecommendItemVo.builder()
                .bookId(bookInfo.getInteger("id"))
                .bookTitle(bookInfo.getString("title"))
                .bookAuthor(bookInfo.getString("author"))
                .bookCover(bookInfo.getString("cover"))
                .bookCategory(bookInfo.getString("categoryName"))
                .recommendScore(score != null ? score : 0.0)
                .build();
    }

    /**
     * 去重并限制数量
     */
    private List<RecommendItemVo> deduplicateAndLimit(List<RecommendItemVo> items, int limit) {
        return items.stream()
                .collect(Collectors.toMap(
                        RecommendItemVo::getBookId,
                        item -> item,
                        (existing, replacement) -> existing))
                .values()
                .stream()
                .limit(limit)
                .collect(Collectors.toList());
    }

    /**
     * 提取图书ID集合
     */
    private Set<Integer> getBookIds(List<RecommendItemVo> items) {
        return items.stream()
                .map(RecommendItemVo::getBookId)
                .collect(Collectors.toSet());
    }
}

